﻿using System;
using System.Globalization;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Xml;
using System.Reflection;
using Services;
using Utilities.Menu.UIElements;
using SuperTicTacToe.Resources;
using Services.Menu;
using Utilities;
using SuperTicTacToe.Menu;

namespace SuperTicTacToe
{
    public class ModelWithWorld
    {
        Matrix world;
        Model model;
        public ModelWithWorld(Model model, Matrix world)
        {
            this.model = model;
            this.world = world;
        }
        public void Draw(Matrix view, Matrix projection)
        {
            model.DrawModel(world, view, projection);
        }
    }
    public class Tile3D
    {
        public Vector3 position;
        
        public BoundingSphere boundingSphere;
    }
    
    public class Level3D : DrawableGameComponent//CameraConsumer
    {
        float CUBE_DISTANCE = 35f;

        protected InputManager input_manager;
        protected SpriteBatch spriteBatch;
        //protected StateManager stateManager;
        
        protected SpriteFont arialHuge, arial18, arial14, arial10, arial16, arial12;
        MyButton menu;
        //MyButton title;

        protected float press_wait;
        protected readonly float PRESS_INTERVAL = 0.5f;
        protected Random rnd;

        protected Texture2D emptyTexture, whiteTexture, whiteBox;
        protected Texture2D background;

        public bool level_ended;
        public Color textColor;
        public Texture2D bgLevel;

        public Vector2 initial_drag_pos, final_drag_pos;

        public float current_zoom;
        float alpha, beta;
        List<ModelWithWorld> cubes;
        
        //Model cube;
        int size = 3;
        Tile3D[, ,] schema;
        Matrix view, projection;
        ArrayList<Player> players;
        StateManager stateManager;
        public Level3D(Game game, StateManager stateManager, ArrayList<Player> players, int size)
            : base(game)
        {
            Game.Services.RemoveService(typeof(InputManager));
            Game.Services.RemoveService(typeof(IInputManager));
            input_manager = new InputManager(Game);
            Game.Components.Add(input_manager);
            this.players = players;
            this.stateManager = stateManager;
            this.size = size+3;
        }

        public override void Initialize()
        {
          
            spriteBatch = Game.Services.GetService(typeof(SpriteBatch)) as SpriteBatch;
            stateManager = Game.Services.GetService(typeof(AStateManager)) as StateManager;

            //Game.Components.Add(new CameraProvider(Game, CameraProvider.FIELDOFVIEW.PROSPECTIVE));

            input_manager.OnTap += on_tap;
            input_manager.OnDrag += on_drag;
            input_manager.OnVerticalDrag += on_drag;
            input_manager.OnHorizontalDrag += on_drag;
            input_manager.OnDragCompleted += on_drag_completed;
            input_manager.OnDoubleTap += on_double_tap;
            input_manager.OnPinch += on_pinch;

          
            base.Initialize();
        }
        protected override void Dispose(bool disposing)
        {
            Game.Services.RemoveService(typeof(IInputManager));
            base.Dispose(disposing);
        }
        public void DisposeMenu()
        {
            Game.Services.RemoveService(typeof(IInputManager));
            Game.Components.Remove(input_manager);
            this.Dispose();
        }

        protected override void LoadContent()
        {
            
            var cube = Game.Content.Load<Model>("Models/cubo");
            arialHuge = Game.Content.Load<SpriteFont>("Fonts/ArialHuge");
            arial18 = Game.Content.Load<SpriteFont>("Fonts/Arial18Ptx");
            arial16 = Game.Content.Load<SpriteFont>("Fonts/Arial16Ptx");
            arial14 = Game.Content.Load<SpriteFont>("Fonts/Arial14Ptx");
            arial10 = Game.Content.Load<SpriteFont>("Fonts/Arial10Ptx");
            arial12 = Game.Content.Load<SpriteFont>("Fonts/Arial12Ptx");
            emptyTexture = Game.Content.Load<Texture2D>("Textures/emptyPixel");
            whiteTexture = Game.Content.Load<Texture2D>("Textures/whitePixel");


            whiteBox = Game.Content.Load<Texture2D>("Textures/bar_box");


            bgLevel = Game.Content.Load<Texture2D>("Textures/LevelBackground");

            stateManager = Game.Services.GetService(typeof(AStateManager)) as StateManager;

            rnd = new Random();

            menu = new MyButton(new Rectangle(100, 200, 150, 60), Strings.Menu, Color.Black, arial14, TextPos.Center, whiteBox, Color.Black);

            //title = new MyButton(new Rectangle(0, 0, 480, 50), Name, textColor, arial18);

            cubes = new List<ModelWithWorld>();
            switch (size)
            {
                case 3:
                    //cubes.Add(new ModelWithWorld(cube, Matrix.CreateTranslation(new Vector3(-CUBE_DISTANCE, -CUBE_DISTANCE, -CUBE_DISTANCE))));
                    //cubes.Add(new ModelWithWorld(cube, Matrix.CreateTranslation(new Vector3(0, 0, 0))));
                    cubes.Add(new ModelWithWorld(cube, Matrix.CreateTranslation(new Vector3(0, -CUBE_DISTANCE, 0))));
                    cubes.Add(new ModelWithWorld(cube, Matrix.CreateTranslation(new Vector3(CUBE_DISTANCE, 0, CUBE_DISTANCE))));
                    break;
            }
            schema = new Tile3D[size, size, size];
            projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver2, GraphicsDevice.Viewport.Width / (float)GraphicsDevice.Viewport.Height, 0.1f, 1000f);
            view = Matrix.CreateLookAt(new Vector3(0, 0, 100) + Vector3.Up, Vector3.Zero, Vector3.Up);
            base.LoadContent();
            
        }
        
        
        public virtual void Reset()
        {
            Game.Services.RemoveService(typeof(InputManager));
            Game.Components.Remove(input_manager);
            Game.Components.Add(input_manager);

            LoadContent();
        }

        public override void Update(GameTime gameTime)
        {

            var dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
            if (press_wait < PRESS_INTERVAL)
                press_wait += dt;

            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            {
                stateManager.SelectMainMenu();
                return;
            }

            var x = (float)(100 * Math.Sin(alpha) * Math.Cos(beta));
            var y = (float)(100 * Math.Sin(alpha) * Math.Sin(beta));
            var z = (float)(100 * Math.Cos(alpha));

            view = Matrix.CreateLookAt(new Vector3(x, 20, z) + Vector3.Up, Vector3.Zero, Vector3.Up);
            //view = Matrix.CreateLookAt(new Vector3(10, 20, 50), Vector3.Zero, Vector3.Up);
            base.Update(gameTime);
        }

        Rectangle bgRect = new Rectangle(0, 0, 480, 800);
        public override void Draw(GameTime gameTime)
        {
            GraphicsDevice.DepthStencilState = DepthStencilState.Default;
            GraphicsDevice.Clear(Color.Azure);
            spriteBatch.Begin();
            menu.Draw(spriteBatch);
            spriteBatch.End();


            for (int i = 0; i < cubes.Count; i++)
                cubes[i].Draw(view, projection);
            var s = Game.Content.Load<Model>("Models/sphere rossa");
            
            s.DrawModel(Matrix.CreateTranslation(10,10,10), view, projection);
            base.Draw(gameTime);
        }
        
        Point tp = new Point();
        protected void on_tap(Vector2 tap)
        {
            if (press_wait < PRESS_INTERVAL || level_ended) return;
            tp.X = (int)tap.X;
            tp.Y = (int)tap.Y;
            if (menu.tapped_on(tp))
                exit_level();




            Vector3 near = GraphicsDevice.Viewport.Unproject(new Vector3(tap.X, tap.Y, 0),
                    projection,
                    view,
                    Matrix.Identity);
            Vector3 far = GraphicsDevice.Viewport.Unproject(new Vector3(tap.X, tap.Y, 1),
                    projection,
                    view,
                    Matrix.Identity);
            Ray ray = new Ray(near, Vector3.Normalize(far - near));
            //Console.WriteLine(ts.boundingSphere.Intersects(ray).HasValue);
            bool finish = false;
            for (int i = 0; i < size && !finish; i++)
            {
                //var t = tiles[i];
                //if (t.boundingSphere.Intersects(ray).HasValue)
                //{
                //}
            }
                            
        }
        

        //bool zoomed_in = false;
        void on_drag(Vector2 drag_pos)
        {


            if (initial_drag_pos != Vector2.Zero)
            {
                var deltax = drag_pos.X - initial_drag_pos.X;
                //var deltay = drag_pos.Y - initial_drag_pos.Y;
                alpha -= deltax/1000;
                alpha = alpha % 360;
                //beta -= deltay/100;
                beta = beta % 360;
            }
            initial_drag_pos = drag_pos;

        }


        
        void on_drag_completed()
        {

            initial_drag_pos = Vector2.Zero;
        }
        
        void on_double_tap(Vector2 tap_position)
        {
            //if (zoomed_in)
            //    current_zoom = MIN_ZOOM;
            //else
            //    current_zoom = MAX_ZOOM;
            //zoomed_in = !zoomed_in;
        }
        void on_pinch(Vector2 position1, Vector2 position2, Vector2 delta1, Vector2 delta2)
        {

                //var temp = current_zoom - (Vector2.Distance(position1, position2) - Vector2.Distance(position1 - delta1, position2 - delta2)) * .01f;

                //current_zoom = Math.Max(MAX_ZOOM, Math.Min(MIN_ZOOM, temp));
        }
        
        public virtual void exit_level(){
            stateManager.SelectMainMenu();
        }
    }


}
